/******************************************************************************

*(C) Copyright 2018 AirM2M International Ltd.

* All Rights Reserved

******************************************************************************
*  Filename:
*
*  Description:
*
*  History: initiated by xxxx
*
*  Notes:
*
******************************************************************************/

/*----------------------------------------------------------------------------*
 *                    INCLUDES                                                *
 *----------------------------------------------------------------------------*/
#include "cmsis_os2.h"
#include "hal_misc.h"
#include "sctdef.h"
#include "clock.h"
#include "sctdef.h"

/*----------------------------------------------------------------------------*
 *                    MACROS                                                  *
 *----------------------------------------------------------------------------*/

#define PLAT_DLY_CODE_IN_RAM  SECTION_DEF_IMPL(.sect_platdelay_text) SECTION_DEF_RAMCODE


/*----------------------------------------------------------------------------*
 *                    DATA TYPE DEFINITION                                    *
 *----------------------------------------------------------------------------*/



/*----------------------------------------------------------------------------*
 *                      GLOBAL VARIABLES                                      *
 *----------------------------------------------------------------------------*/
extern uint32_t SystemCoreClock;

const uint32_t table[256]={
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
};

/*----------------------------------------------------------------------------*
 *                      PRIVATE FUNCTION DECLEARATION                         *
 *----------------------------------------------------------------------------*/

extern uint32_t GPR_getChipFullID(void);
extern uint32_t GPR_getChipRevID(void);
extern uint32_t GPR_getChipID(void);

/*----------------------------------------------------------------------------*
 *                      PRIVATE FUNCTIONS                                     *
 *----------------------------------------------------------------------------*/

/*
 *  cpu cycles delay, every loop spends 2 cpu cycles, so the actual delay is 2*cycles
 *  Parameter: cycles
 */

#if defined(__CC_ARM)
__asm static void delay_cycles(uint32_t cycles)
{
loop
    SUBS r0, r0, #1
    BNE loop
    BX lr
}
#elif defined (__GNUC__)
PLAT_DLY_CODE_IN_RAM static void delay_cycles(uint32_t cycles)
{
asm volatile(
    "mov r0, %0\n\t"
    "loop:\n\t"
    "SUBS r0, r0, #1\n\t"
    "BNE loop\n\t"
    : : "r" (cycles)
);
}
#endif


/*----------------------------------------------------------------------------*
 *                      GLOBAL FUNCTIONS                                      *
 *----------------------------------------------------------------------------*/

/**
  \fn        HAL_Get_ChipID(chip_id_sel sel)
  \brief     Get chip id.
  \param[in] HAL_Get_ChipID enum
  \note
   31-----8 is chip id
   7------0 is revision id
   sel=CHIP_ID_ONLYID, return chip id
   sel=CHIP_ID_REVID,  return revision id
   sel=CHIP_ID_FULL, return both revision and chip id
 */
uint32_t HAL_Get_ChipID(chip_id_sel sel)
{
   uint32_t chipID=0;


   switch(sel)
   {
       case CHIP_ID_ONLYID:

           chipID=GPR_getChipID();
           break;

       case CHIP_ID_REVID:
           chipID=GPR_getChipRevID();
           break;

       case CHIP_ID_FULLID:

           chipID=GPR_getChipFullID();
           break;

       default:
           break;
    }

   return chipID;

}




/**
  \fn        delay_us(uint32_t us)
  \brief     delay time in microseconds.
  \param[in] number of us
  \note       Given the maximum cpu frequency is 204.8MHz and the limit in calculation,
 *            the maximum time can be delayed is 0xFFFFFFFF / 2048 = 2097151 us = 2097 m
 */
PLAT_DLY_CODE_IN_RAM void delay_us(uint32_t us)
{
    uint32_t ticks;

    // cpu frequency ranges from 26MHz to 306MHz
    // first divide 0.1M to get rid of multiply overflow
    // considering 3 cpu cycles are taken to execute one loop operation(sub and branch) in delay_cycles function(includ one pre read assembly),
    // and 0.1M in first step, so we shall divide another 30 before passing the result to delay_cycles function
    // if the delay us is short, it may not be accurate
    ticks = SystemCoreClock / 100000U;
    ticks = ticks * us / 30U;

    delay_cycles(ticks);
}

__attribute__((used)) PLAT_DLY_CODE_IN_RAM void delay_100ns(uint32_t n100ns)
{
    uint32_t ticks;

    // cpu frequency ranges from 26MHz to 306MHz
    // first divide 0.1M to get rid of multiply overflow
    // considering 3 cpu cycles are taken to execute one loop operation(sub and branch) in delay_cycles function(includ one pre read assembly),
    // and 0.1M in first step, so we shall divide another 300 before passing the result to delay_cycles function
    // if the delay us is short, it may not be accurate
    ticks = SystemCoreClock / 100000U;
    ticks = ticks * n100ns / 300U;

    delay_cycles(ticks);
}



/**
  \fn        apmuBootDbgGPIOSet(bool level)
  \brief     set gpio level in boot flow, for boot time dbg
  \param[in] gpio level
  \note       should set register directly, do not use api
 */
void apmuBootDbgGPIOSet(bool level)
{
#if 0
    volatile uint32_t *apb_mp_pclken = (volatile uint32_t *)0x4f000030;
	volatile uint32_t *xpsys_clken = (volatile uint32_t *)0x40000008;
    (*apb_mp_pclken) |= (1<<6);  // pclk pad
	(*xpsys_clken) |= (1<<12);  // gpio rmi hclk
    GPIO_TypeDef *base = (GPIO_TypeDef *)0x40040000;	//gpio instance 0
    base->OUTENSET = (1<<7);
    base->DATAOUT = (level<<7);
#endif
}

PLAT_PA_RAMCODE void apmuBootDbgGPIOSetRamcode(bool level)
{
#if 0
    volatile uint32_t *apb_mp_pclken = (volatile uint32_t *)0x4f000030;
	volatile uint32_t *xpsys_clken = (volatile uint32_t *)0x40000008;
    (*apb_mp_pclken) |= (1<<6);  // pclk pad
	(*xpsys_clken) |= (1<<12);  // gpio rmi hclk
    GPIO_TypeDef *base = (GPIO_TypeDef *)0x40040000;	//gpio instance 0
    base->OUTENSET = (1<<6);
    base->DATAOUT = (level<<6);
#endif
}

/**
  \fn        bool apmuGetLongSlpCfg(void)
  \brief     config the maximum sleep length.
             1. We suggest return false to sleep no more than 291.2hour
             2. But when usb is disabled and you do not care about time accuracy,
             return true to set maximum sleep time to 9320 hour
  \note      false: sleep no more than 291.2 hour, true:  can sleep 9320 hour
 */
#ifdef __USER_CODE__
__attribute__((weak)) bool apmuGetLongSlpCfg(void)
{
	return true;
}
#else
bool apmuGetLongSlpCfg(void)
{
    return false;
}
#endif

PLAT_PA_RAMCODE ClockId_e CLOCK_checkClkID(void)
{
    return INVALID_CLK;
}


/**
  \fn        halCrc32(void* input, int len)
  \brief     caculate the crc 32
  \param[in] input pointer to input buffer
             len buffer len
  \note
 */
PLAT_BL_CIRAM_FLASH_TEXT uint32_t halCrc32(void* input, int len)
{
    int i;
    uint8_t index;
    uint8_t *p;
    uint32_t crc;

    crc=0xFFFFFFFF;

    p = (uint8_t*)input;
    for(i=0; i<len; i++)
    {
        index = (*p ^ crc);
        crc = (crc >> 8) ^ table[index];
        p++;
    }
    return crc^0xFFFFFFFF;
}



/**
  \fn        halVoiceEngProcRetWrapper(UINT16 msgId, void *pIpcRet)
  \brief     used as wrapper API for halVoiceEngProcRet
             FEATURE_AUDIO_ENABLE could only be used in open source code
  \note
 */
#ifdef __USER_CODE__	//no audio enable also can use, for csdk
__attribute__((weak))  void halVoiceEngProcRet(UINT16 msgId, void *pIpcRet) {;}
#endif
void halVoiceEngProcRetWrapper(UINT16 msgId, void *pIpcRet)
{
#ifdef __USER_CODE__
    extern void halVoiceEngProcRet(UINT16 msgId, void *pIpcRet);
    halVoiceEngProcRet(msgId, pIpcRet);
#else
    #ifdef FEATURE_AUDIO_ENABLE
    extern void halVoiceEngProcRet(UINT16 msgId, void *pIpcRet);
    halVoiceEngProcRet(msgId, pIpcRet);
    #else
    return;
    #endif
#endif
}



/**
  \fn        txPwrIndCustHandler(int8_t txPwr, uint8_t level)
  \brief     indication to customer for tx power change, customer add specific process
             in this API.
  \param[in] txPwr: current tx power @ -45--23 dbm
             level: 1 means above high threshold 
                    0 means below low threshold
  \note      this API is called in EC internal task, should not add time cost operation!!
             suggest to send msg to customer defined task to do the real process logic.
 */
__WEAK void txPwrIndCustHandler(int8_t txPwr, uint8_t level){};

